package com.gotokeep.gyromousedemo

import android.util.Log
import com.gotokeep.gyromousedemo.EventType.TYPE_MOVE
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.math.abs

class DataSender(ip: String, private val port: Int) {

    private val localScope = CoroutineScope(EmptyCoroutineContext)
    private val serverAddress = InetAddress.getByName(ip)
    private val socket = DatagramSocket()

    private val messageFlow = MutableSharedFlow<String>()
    private var lastTimeStamp = 0L
    private var lastPositions = FloatArray(3)

    init {
        messageFlow
            .onEach { message ->
                kotlin.runCatching {
                    val dataPacket =
                        DatagramPacket(message.toByteArray(), message.length, serverAddress, port)
                    socket.send(dataPacket)
                }.apply {
                    Log.e(
                        TAG,
                        "frameRate->send data with msg: $message with result->${exceptionOrNull()}"
                    )
                }
            }
            .launchIn(localScope)
    }

    fun sendMessage(eventType: EventType, values: FloatArray) {
        val currentTimeMillis = System.currentTimeMillis()
        // 限制过小波动的数据发送，没有意义
        if (eventType == TYPE_MOVE) {
            var valid = false
            for (i in values.indices) {
                val currentValue = values[i]
                val lastValue = lastPositions[i]
                if (abs(currentValue - lastValue) >= MIN_VALUE) {
                    valid = true
                    break
                }
            }
            if (!valid) {
                return
            }
            // 限制发送间隔，没必要发送太频繁
            if (currentTimeMillis - lastTimeStamp < MIN_INTERVAL_IN_MILLIS) {
                return
            }
        }
        lastPositions = values
        lastTimeStamp = currentTimeMillis
        localScope.launch {
            messageFlow.emit(getDataString(eventType, values))
        }
    }

    fun release() {
        socket.close()
        localScope.cancel()
    }

    companion object {

        private const val TAG = "DataSender"
        private const val MIN_INTERVAL_IN_MILLIS = 10
        private const val MIN_VALUE = 0.001f

        private fun getDataString(eventType: EventType, values: FloatArray): String {
            return "${eventType.ordinal}${AppContext.DIVIDER}${values[0]}${AppContext.DIVIDER}${values[1]}${AppContext.DIVIDER}${values[2]}"
        }
    }
}
